package gnssio

import (
	"dgo/goutils/utils"
	"errors"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"net/url"
	"strings"
	"time"
)

func init() {
	utils.RegisterCreate("tcp://", CreateTcpClientCommFromCmdLineFunc)
	utils.RegisterCreate("tcpsvr://", CreateTcpSvrCommFromCmdLineFunc)
	utils.RegisterCreate("tcpsvr2://", CreateASyncTcpSvrCommFromCmdLineFunc)
	utils.RegisterCreate("com://", CreateSerialCommFromCmdLineFunc)
	utils.RegisterCreate("ntripsvr://", CreateNtripSvrCommFromCmdLineFunc)
	utils.RegisterCreate("ntrip2svr://", CreateNtrip2SvrCommFromCmdLineFunc)
	utils.RegisterCreate("ntripclt://", CreateNtripCltCommFromCmdLineFunc)
	utils.RegisterCreate("ntripcltex://", MakeCreateCommLineFunc(NewCommNtripCltExFromCmd))
	utils.RegisterCreate("filew://", CreateFileWriterCommFromCmdLineFunc)
	utils.RegisterCreate("filewEx://", CreateFileWriterCommFromCmdLineFuncEx)
	utils.RegisterCreate("fileREW://", CreateFileREWCommFromCmdLineFunc)
	//utils.RegisterCreate("obsFileW://", CreateObsFileWCommFromCmdLineFunc)
	utils.RegisterCreate("tasksender://", CreateTaskSenderCommFromCmdLineFunc)
	utils.RegisterCreate("rsa-en-pub://", CreateCommRSAEncrptPublicFunc)
	utils.RegisterCreate("rsa-de-pri://", CreateCommRSADecrptPrivateFunc)
	utils.RegisterCreate("nmeagetter://", CreateNMEAGetterCommFromCmdLineFunc)
	utils.RegisterCreate("multichannel://", CreateCommMultiChannelFromCmdLineFunc)
}

type TCreateCommFromCmdLineFunc func(cmdstr string) (interface{}, error)

func CreateCommFromCmdLineAndConf(cmdLine, cmdLineconf string) (I_Comm, error) {
	if len(cmdLineconf) > 0 {
		escapstr := utils.QueryEscapeUrl(cmdLineconf)
		cmdLine += "/" + escapstr
	}
	return CreateCommFromCmdLine(cmdLine)
}

func CreateCommFromCmdLine(cmdLine string) (I_Comm, error) {
	strs := strings.SplitN(cmdLine, "//", 2)
	if len(strs) != 2 {
		return nil, errors.New("非法的命令符")
	}
	ins, err := utils.CreateInstance(strs[0]+"//", cmdLine)
	if ins == nil || err != nil {
		return nil, err
	}

	if rval, ok := ins.(I_Comm); ok {
		return rval, nil
	}

	return nil, errors.New(fmt.Sprintf("创建(%s)I_COMM失败", cmdLine))
}

/*
**

	nmeagetter://COMM_CMD_LINE
	COMM_CMD_LINE like tcp://ip:port[/tagstr]
*/
func NewCommNMEAGetterFromCmd(cmdstr string) *CommNMEAGetter {
	ok, cmdstr := utils.CheckTrimPrefix(cmdstr, "nmeagetter://")
	if !ok {
		return nil
	}

	if len(cmdstr) == 0 {
		return nil
	}

	incomm, _ := CreateCommFromCmdLine(cmdstr)
	if incomm == nil {
		return nil
	}

	rval := NewCommNMEAGetter()
	rval.SetInnerDataComm(incomm)
	return rval
}

/*
**

	tasksender://1000/hex:00FF0D13/COMM_CMD_LINE
	COMM_CMD_LINE like tcp://ip:port[/tagstr]
*/
func NewCommTaskSenderFromCmd(cmdstr string) *CommTaskSender {
	ok, cmdstr := utils.CheckTrimPrefix(cmdstr, "tasksender://")
	if !ok {
		return nil
	}

	if len(cmdstr) == 0 {
		return nil
	}

	strs := strings.SplitN(cmdstr, "/", 3)
	if len(strs) < 3 {
		return nil
	}

	cmdstr = strs[2]
	incomm, _ := CreateCommFromCmdLine(cmdstr)
	if incomm == nil {
		return nil
	}

	interval := time.Duration(utils.StrToIntDef(strs[0], 1000)) * time.Millisecond
	var buff []byte
	ok, hexstr := utils.CheckTrimPrefix(strs[1], "hex:")
	if !ok {
		str := strs[1]
		strOK, err := url.QueryUnescape(str)
		if err != nil {
			buff = []byte(str)
		} else {
			buff = []byte(strOK)
		}
		utils.Log.Infof("tasksender:[%s]", string(buff))

	} else {
		buff = utils.HexStrToBuf(hexstr)
	}

	rval := NewCommTaskSender(interval, buff)
	rval.SetInnerDataComm(incomm)
	return rval
}

/*
**

	filew://[isutc]/[file]
*/
func NewCommFileWFromCmd(cmdstr string) *CommRawFileWriter {
	ok, cmdstr := utils.CheckTrimPrefix(cmdstr, "filew://")
	if !ok {
		return nil
	}

	if len(cmdstr) == 0 {
		return nil
	}

	strs := strings.SplitN(cmdstr, "/", 2)
	if len(strs) < 2 {
		return nil
	}

	rval := NewRawFileWriter(strs[1])
	rval.IsUtcTime = (utils.StrToIntDef(strs[0], 1) == 1)
	return rval
}

/*
**

	filewEx://{conf}/[file]
*/
func NewCommFileWFromCmdEx(cmdstr string) *CommRawFileWriter {
	ok, cmdstr := utils.CheckTrimPrefix(cmdstr, "filewEx://")
	if !ok {
		return nil
	}

	if len(cmdstr) == 0 {
		return nil
	}

	strs := strings.SplitN(cmdstr, "/", 2)
	if len(strs) < 2 {
		return nil
	}

	rval := NewRawFileWriter(strs[1])
	if len(strs[0]) > 0 {
		strConf, _ := utils.QueryUnescape(strs[0])
		json, err := wrapper.NewSVFromBuf([]byte(strConf))
		if err == nil {
			rval.IsUtcTime = json.IntByName("isutc", 0) == 1
			rval.WBufSize = json.IntByName("bufsize", 0)
		}
	}

	return rval
}

/*
**

	fileREW://[isutc]/[file]
*/
func NewCommFileREWFromCmd(cmdstr string) *CommRawFileReWriter {
	ok, cmdstr := utils.CheckTrimPrefix(cmdstr, "fileREW://")
	if !ok {
		return nil
	}

	if len(cmdstr) == 0 {
		return nil
	}

	strs := strings.SplitN(cmdstr, "/", 2)
	if len(strs) < 2 {
		return nil
	}

	rval := NewRawFileReWriter(strs[1])
	rval.IsUtcTime = (utils.StrToIntDef(strs[0], 1) == 1)
	return rval
}

// /***
//   obsFileW://[writetype]/[file]
// */
// func NewCommObsFileWFromCmd(cmdstr string) *CommRtcmObsWriter {
// 	ok, cmdstr := utils.CheckTrimPrefix(cmdstr, "obsFileW://")
// 	if !ok {
// 		return nil
// 	}

// 	if len(cmdstr) == 0 {
// 		return nil
// 	}

// 	strs := strings.SplitN(cmdstr, "/", 2)
// 	if len(strs) < 2 {
// 		return nil
// 	}

// 	rval := NewCommRtcmObsWriter(strs[1], 0)
// 	rval.writeType = utils.StrToIntDef(strs[0], 0)
// 	return rval
// }

/*
**

	ntripclt://USER:PASS@IP:PORT/MOUNTPOINT[/GGA][/config]
*/
func NewCommNtripTcpClientFromCmd(cmdstr string) *CommNtripClient {
	ok, cmdstr := utils.CheckTrimPrefix(cmdstr, "ntripclt://")
	if !ok {
		return nil
	}

	strs := strings.SplitN(cmdstr, "/", 4)
	if len(strs) < 2 {
		return nil
	}
	strConnectString := strs[0]
	strMnt := strs[1]
	strGGA := ""
	strConf := ""
	if len(strs) >= 3 {
		strGGA = strs[2]
	}
	if len(strs) >= 4 {
		strConf, _ = utils.QueryUnescape(strs[3])

	}

	rval := NewCommNtripClient_0()
	rval.SetConnectString(strConnectString)
	rval.SetNMEA(strGGA)
	rval.SetConfig(strConf)
	rval.client.SetRequestMountPoint(strMnt)

	return rval
}

func CreateNtripCltCommFromCmdLineFunc(args ...interface{}) (rval interface{}, err error) {
	if len(args) < 1 {
		return nil, errors.New("至少要传入一个参数")
	}
	cmdStr := args[0].(string)
	if len(cmdStr) == 0 {
		return nil, errors.New("命令参数非法")
	}
	return NewCommNtripTcpClientFromCmd(cmdStr), nil
}

func CreateFileREWCommFromCmdLineFunc(args ...interface{}) (rval interface{}, err error) {
	if len(args) < 1 {
		return nil, errors.New("至少要传入一个参数")
	}
	cmdStr := args[0].(string)
	if len(cmdStr) == 0 {
		return nil, errors.New("命令参数非法")
	}
	return NewCommFileREWFromCmd(cmdStr), nil
}

// func CreateObsFileWCommFromCmdLineFunc(args ...interface{}) (rval interface{}, err error) {
// 	if len(args) < 1 {
// 		return nil, errors.New("至少要传入一个参数")
// 	}
// 	cmdStr := args[0].(string)
// 	if len(cmdStr) == 0 {
// 		return nil, errors.New("命令参数非法")
// 	}
// 	return NewCommObsFileWFromCmd(cmdStr), nil
// }

func CreateFileWriterCommFromCmdLineFuncEx(args ...interface{}) (rval interface{}, err error) {
	if len(args) < 1 {
		return nil, errors.New("至少要传入一个参数")
	}
	cmdStr := args[0].(string)
	if len(cmdStr) == 0 {
		return nil, errors.New("命令参数非法")
	}
	return NewCommFileWFromCmdEx(cmdStr), nil
}

func CreateFileWriterCommFromCmdLineFunc(args ...interface{}) (rval interface{}, err error) {
	if len(args) < 1 {
		return nil, errors.New("至少要传入一个参数")
	}
	cmdStr := args[0].(string)
	if len(cmdStr) == 0 {
		return nil, errors.New("命令参数非法")
	}
	return NewCommFileWFromCmd(cmdStr), nil
}

func CreateTaskSenderCommFromCmdLineFunc(args ...interface{}) (rval interface{}, err error) {
	if len(args) < 1 {
		return nil, errors.New("至少要传入一个参数")
	}
	cmdStr := args[0].(string)
	if len(cmdStr) == 0 {
		return nil, errors.New("命令参数非法")
	}
	return NewCommTaskSenderFromCmd(cmdStr), nil
}

func CreateNMEAGetterCommFromCmdLineFunc(args ...interface{}) (rval interface{}, err error) {
	if len(args) < 1 {
		return nil, errors.New("至少要传入一个参数")
	}
	cmdStr := args[0].(string)
	if len(cmdStr) == 0 {
		return nil, errors.New("命令参数非法")
	}
	return NewCommNMEAGetterFromCmd(cmdStr), nil
}

func MakeCreateCommLineFunc(fn TCreateCommFromCmdLineFunc) func(args ...interface{}) (rval interface{}, err error) {
	return func(args ...interface{}) (rval interface{}, err error) {
		if len(args) < 1 {
			return nil, errors.New("至少要传入一个参数")
		}
		cmdStr := args[0].(string)
		if len(cmdStr) == 0 {
			return nil, errors.New("命令参数非法")
		}

		return fn(cmdStr)
	}
}
